<template>
  <slot name="header"></slot>
  <a-form v-bind="_options" ref="formRef" :model="model" @submit.prevent>
    <a-row v-bind="rowProps" :gutter="20">
      <template
        v-for="{ field, component, formItemProps, componentProps, lists, colProps } in newFieldList"
        :key="field"
      >
        <!-- 单选框 -->
        <a-col v-if="component === 'radio'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-radio-group v-bind="componentProps" v-model="model[field]">
              <a-radio v-for="val in lists" :key="val['value']" :label="val['value']" size="large">
                {{ val['label'] }}
              </a-radio>
            </a-radio-group>
          </a-form-item>
        </a-col>
        <!-- 复选框 -->
        <a-col v-if="component === 'checkbox'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-checkbox-group v-bind="componentProps" v-model="model[field]">
              <a-checkbox v-for="c in lists" :key="c['value']" :label="c['value']">{{ c['label'] }}</a-checkbox>
            </a-checkbox-group>
          </a-form-item>
        </a-col>
        <!-- 下拉框 -->
        <a-col v-if="component === 'select'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-select v-bind="componentProps" v-model="model[field]">
              <a-option v-for="s in lists" :key="s['value']" :label="s['label']" :value="s['value']" />
            </a-select>
          </a-form-item>
        </a-col>
        <!-- 文本域 -->
        <a-col v-if="component === 'textarea'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-textarea v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 时间选择器 -->
        <a-col v-if="component === 'time'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-time-picker v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 日期选择器 -->
        <a-col v-if="component === 'date'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-date-picker v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 日期范围选择器 -->
        <a-col v-if="component === 'rangeDate'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-range-picker v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 级联选择器 -->
        <a-col v-if="component === 'cascader'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-cascader v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 数字输入框 -->
        <a-col v-if="component === 'inputNumber'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-input-number v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 输入框 -->
        <a-col v-if="component === 'input'" v-bind="colProps">
          <a-form-item v-bind="formItemProps">
            <a-input v-bind="componentProps" v-model="model[field]" />
          </a-form-item>
        </a-col>
        <!-- 标题模块 -->
        <a-col v-if="component === 'title'" :span="24">
          <div class="title">
            <div class="bar"></div>
            <h4 class="text">{{ formItemProps.label }}</h4>
          </div>
        </a-col>
        <!-- 自定义插槽slot -->
        <a-col v-if="component === 'slot'" :span="24">
          <slot :name="field"></slot>
        </a-col>
      </template>
      <a-col :span="24">
        <a-form-item>
          <slot name="buttons" :model="model" :formRef="formRef">
            <a-space>
              <a-button type="primary" @click="onSubmit(formRef)">{{ _options.submitButtonText }}</a-button>
              <a-button v-if="_options.showResetButton" @click="resetForm(formRef)">
                {{ _options.resetButtonText }}
              </a-button>
              <a-button v-if="_options.showCancelButton" @click="emit('cancel')">
                {{ _options.cancelButtonText }}
              </a-button>
            </a-space>
          </slot>
        </a-form-item>
      </a-col>
    </a-row>
  </a-form>
  <slot name="footer"></slot>
</template>
<script lang="ts" setup>
import type { FormInstance, RowProps, ValidatedError } from '@arco-design/web-vue';
import type { ComputedRef } from 'vue';
import type { Form } from './interface';
import { formItemKeys, customKeys, COL_PROPS } from './constants';
import { changeFormList } from './utils';
import type { FieldData } from '@arco-design/web-vue/es/form/interface';
// 父组件传递的值
interface Props {
  fieldList: Form.FieldItem[];
  model?: Record<string, any>;
  options?: Form.Options;
  rowProps?: RowProps;
}
interface EmitEvent {
  (e: 'submit' | 'change', params: any): void;
  (e: 'reset' | 'cancel'): void;
}

const props = defineProps<Props>();
const emit = defineEmits<EmitEvent>();
// 表单的数据
let model = ref<Record<string, any>>({});

const formRef = ref<FormInstance>();

// 初始化处理Form组件属性options
const _options = ref<Record<string, any>>({});
const initOptions = () => {
  const option = {
    layout: 'vertical',
    disabled: false,
    submitButtonText: '提交',
    resetButtonText: '重置',
    cancelButtonText: '取消',
    showResetButton: true,
  };
  Object.assign(option, props?.options);
  _options.value = option;
};
initOptions();
// 初始化处理model
const initFormModel = () => {
  props.fieldList.forEach((item: Form.FieldItem) => {
    // 如果类型为checkbox，默认值需要设置一个空数组
    const value = item.component === 'checkbox' ? [] : '';
    const { field, component } = item;
    if (component !== 'slot' && component !== 'title') {
      model.value[item.field] = props?.model?.[field] || value;
    }
  });
};
initFormModel();
// 初始化处理fieldList
const newFieldList: any = ref(null);
const initFieldList = () => {
  const list = props?.fieldList.map((item: Form.FieldItem) => {
    const customProps = pick(item, customKeys);
    const formItemProps = pick(item, formItemKeys);
    const componentProps = omit(item, [...formItemKeys, ...customKeys, 'field', 'colProps']);
    const { colProps = {}, field, placeholder, component = 'input', label } = item;
    componentProps.onChange = (val: any) => onChange(field, val);
    const newColProps = {
      ...colProps,
      ...COL_PROPS,
    };
    const obj = {
      field,
      colProps: newColProps,
      ...customProps,
      formItemProps,
      componentProps,
    };
    if ((component === 'input' || component === 'textarea') && !placeholder) {
      componentProps.placeholder = `请输入${label}`;
    }
    if (component === 'select' && !placeholder) {
      componentProps.placeholder = `请选择${label}`;
    }
    if (component === 'rangeDate') {
      componentProps.value = [null, null];
    }
    return obj;
  });
  newFieldList.value = list;
  return list;
};
initFieldList();
// 提交
const onSubmit = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  let flag = false;
  await formEl.validate((errors: undefined | Record<string, ValidatedError>) => {
    if (!errors) {
      emit('submit', model.value);
      flag = true;
    } else {
      return false;
    }
  });
  return (flag && model.value) || null;
};
// 提交--父组件调用
const submit = () => {
  return onSubmit(formRef.value);
};
// 重置
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.resetFields();
};
// 表单变化
const onChange = (key: string, val: any) => {
  emit('change', { key, val });
};
// 设置
const setModel = (data: Record<string, FieldData>) => {
  const newData = {
    ...model.value,
    ...data,
  };
  model.value = newData;
};
// 设置Form
const setForm = (data: Form.Options) => {
  const options = {
    ..._options.value,
    ...data,
  };
  _options.value = options;
};
// 更新配置项
const updateFieldsList = (updateList: any[]) => {
  const list = changeFormList(newFieldList.value, updateList);
  newFieldList.value = list;
};

defineExpose({
  submit,
  setModel,
  setForm,
  updateFieldsList,
});
</script>
<style lang="less" scoped>
:deep(.arco-picker) {
  width: 100%;
}
.title {
  display: flex;
  align-items: center;
  .bar {
    width: 4px;
    height: 14px;
    border-radius: 1px;
    margin-right: 8px;
    background-color: rgb(var(--primary-6));
  }
  .text {
    font-size: 16px;
    color: var(--color-text-1);
  }
}
</style>
